﻿/*
 *  RetroGlider v1.0
    Copyright (C) 2013 Alexander Blohmé

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Windows.Forms;
using System.Xml.Linq;
using System.Xml;
using System.Threading;
using OpenHack;
using System.IO;


namespace RetroGlider
{    

    public class WalkEngine
    {     
        [DllImport("user32.dll", SetLastError = true)]
        static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        IntPtr Handle = FindWindow(null, "World of Warcraft");
           
        

        List<string> Waypoints = new List<string>();    // Waypoint array
        List<string> GhostWaypoints = new List<string>();


        //turn within an accuracy of 1/10th rad
        const float turnaccuracy = 0.1f;
        //walk until distance is < 3 ----- Need logic to determine spell range
        const float walkaccuracy = 5;
        bool isTurning = false;
        bool isWalking = false;
        Post.ArrowKeys turnkey;        
        Thread ApproachThread;
        // Timers
        
        public void LoadProfile(string profileName)
        {
            bool addWaypoint = false;
            XmlTextReader reader = new XmlTextReader(profileName);
            while (reader.Read())
            {
                switch (reader.NodeType)
                {

                    case XmlNodeType.Element:
                        if (reader.Name == "Waypoint")
                        {
                            addWaypoint = true;
                        }
                        else
                        {
                            addWaypoint = false;
                        }
                        break;
                    case XmlNodeType.Text:
                        if (addWaypoint == true)
                        {
                            Waypoints.Add(reader.Value);
                        }
                        break;

                }
            }
            foreach (string ses in Waypoints)
            {
                Console.Write(ses + "\n");
            }
        }


        // For start patrol (Go in glider waypoint)
        public void Patrol()
        {
            WoWEngine WoWInformation = new WoWEngine();

            // Patrol here
             

            // ALEX 15.11.2013 - 20:32
            // 
            // Updated function to use a anonymous thread lambda expression for approach.
            // It also scan for mobs until we have a target, then breaks the loop
            (new Thread(() =>
            {
               ApproachThread = new Thread(new ThreadStart(ApproachMob));
               bool mob_found = false;
                    while (true)
                    {

                        // Dont scan for mobs if we have a target in sight
                        if (!WoWInformation.HaveTarget())
                        { 
                            ScanForMob(); 
                        }

                        if (!WoWInformation.HaveTarget())
                        {
                            // Continue to walk


                        }
                        else
                        {
                            // Stop patrolling and let the approach thread do the rest

                        }


                        if (WoWInformation.HaveTarget() && mob_found != true)
                        {
                            mob_found = true;
                            ApproachThread.IsBackground = true;
                            ApproachThread.Start();
                            //break;
                        }

                        // Mob was found and IT DEATHED.. probably ;P
                    
                        if (mob_found && !WoWInformation.HaveTarget())
                        {
                            ApproachThread.Abort();
                           // MessageBox.Show("Mob deathed!");
                        }

                    }
            })).Start();

         }

        public void ApproachMob()
        {
            WoWEngine WoWInformation = new WoWEngine();

            while (WoWInformation.HaveTarget() && WoWInformation.InitWoW())
            {
                Thread.Sleep(5);

                // Approach the targeted mob  

                //get the angle to which we need to turn in order to face our target                
                float a = (float)Math.Atan2(WoWInformation.TargetYPosition() - WoWInformation.PlayerYPosition(), WoWInformation.TargetXPosition() - WoWInformation.PlayerXPosition());

                //if the turning angle is negative
                //(sometimes happens, depending on negative coordinates and such)
                if (a < 0)
                    //add the maximum possible angle (PI x 2) to normalize the negative angle
                    a += (float)(Math.PI * 2);

                //calculate our distance from the object
                double dist = WowObject.GetDistance(WoWInformation.PlayerXPosition(), WoWInformation.PlayerYPosition(), WoWInformation.TargetXPosition(), WoWInformation.TargetYPosition());


                if (WoWInformation.PlayerFacingPosition() < (a + turnaccuracy) && WoWInformation.PlayerFacingPosition() > (a - turnaccuracy))
                {
                    //we're facing it, so walk away!!

                    //if we're turning, stoppit
                    if (isTurning)
                    {
                        isTurning = false;
                        EndTurnRight();
                        EndTurnLeft();

                    }

                    //if we're close to the target
                    if (dist < walkaccuracy)
                    {
                        //if we're walking, stop walking
                        if (isWalking)
                        {
                            StopAllMovement();
                            isWalking = false;
                        }
                        //we're close, don't need to walk
                        //break;
                    }

                    //we're not close, so we're walking
                    isWalking = true;
                    //hold down the up button
                    StartForward(); 

                    //break;
                }
                else
                {
                    //Turn to the mob
                    FaceMob(a);                    
                }
                
                //break;
            }
            
        }

        // To stop ALL movement
        public void StopAllMovement()
        {
            EndBackward();
            EndForward();
            EndTurnLeft();
            EndTurnRight();

        }
        


        void FaceMob(float a)
       {
            WoWEngine WoWInformation = new WoWEngine();

            /*

            int PlayerX = (int)WoWInformation.PlayerXPosition();
            int PlayerY = (int)WoWInformation.PlayerYPosition();

            int TargetX = (int)WoWInformation.TargetXPosition();
            int TargetY = (int)WoWInformation.TargetYPosition();

            if (PlayerX != TargetX || PlayerY != TargetY)
            {
                StartTurnRight();
            }
            */

            //we're not facing it, so we'd better damn well face it

            //if we're walking, we don't want to be, so stoppit
            if (isWalking)
            {
                EndForward();
                isWalking = false;
                //break;
            }

            //if we're already turning, no need to turn again
            //if (isTurning)		//no need to have this enabled
            //	break;				//while debugging

            //we're turning
            isTurning = true;

            //variable definition
            double r, l;

            //if our current facing angle, in radians, is greater than
            //the angle which we desire to face
            if (WoWInformation.PlayerFacingPosition() > a)
            {
                //we'd have to turn past North if we're turning left
                l = ((2 * Math.PI) - WoWInformation.PlayerFacingPosition()) + a;
                //we don't have to turn past North if we're turning right
                r = WoWInformation.PlayerFacingPosition() - a;
            }
            else
            {
                //we don't have to turn past North if we're turning left
                l = a - WoWInformation.PlayerFacingPosition();
                //we have to WoWInformation.PlayerFacingPosition() past North if we're turning right
                r = WoWInformation.PlayerFacingPosition() + ((2 * Math.PI) - a);
            }

            //let's please turn in the direction where we have to spend
            //the least amount of time turning
            if (l < r)
            {
                turnkey = Post.ArrowKeys.Left;
            }
            else
            {
                turnkey = Post.ArrowKeys.Right;
            }

            //hold down the arrow key in the direction we've determined
            //we should be turning
            Post.ArrowKeyDown(Handle, turnkey);


        }

        // Will send TAB key
        public bool ScanForMob()
        {
            Post.SendTab(Handle);
            if ((new WoWEngine()).HaveTarget() == true)
            {
                return true;
            }
            
            return false;
        }

        private void StartTurnLeft()
        {
            Post.ArrowKeyDown(Handle, Post.ArrowKeys.Left);
        }
        private void EndTurnLeft()
        {
            Post.ArrowKeyUp(Handle, Post.ArrowKeys.Left);
        }

        private void StartTurnRight()
        {
            Post.ArrowKeyDown(Handle, Post.ArrowKeys.Right);
        }
        private void EndTurnRight()
        {
            Post.ArrowKeyUp(Handle, Post.ArrowKeys.Right);
        }

        private void StartForward()
        {
            Post.ArrowKeyDown(Handle, Post.ArrowKeys.Up);     
        }

        private void EndForward()
        {
            Post.ArrowKeyUp(Handle, Post.ArrowKeys.Up);
        }

        private void StartBackward()
        {
            Post.ArrowKeyDown(Handle, Post.ArrowKeys.Down);
        }

        private void EndBackward()
        {
            Post.ArrowKeyUp(Handle, Post.ArrowKeys.Down);
        }

        public void RecordWaypoint(string Filename, List<string> waypoints)
        {
            System.IO.File.WriteAllLines(Filename, waypoints);
        }


        

    }
}
